/*
author:杨文超
email:yangwenchao@keynection.cn
*/
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "geminai_log.h"
#include "geminai_spiffs.h"

static const char *TAG = "GEMINAI_SPIFFS";

esp_err_t geminai_spiffs_init(char *mount_point,char *partition_label)
{
    esp_err_t ret;
    GEMINAI_LOGI(TAG, "Initializing SPIFFS");

    esp_vfs_spiffs_conf_t conf = {
        .base_path = mount_point,
        .partition_label = partition_label,
        .max_files = 10,   // This decides the maximum number of files that can be created on the storage
        .format_if_mount_failed = false
    };

    ret = esp_vfs_spiffs_register(&conf);

    if (ret != ESP_OK) {
        if (ret == ESP_FAIL) {
            GEMINAI_LOGE(TAG, "Failed to mount or format filesystem");
        } else if (ret == ESP_ERR_NOT_FOUND) {
            GEMINAI_LOGE(TAG, "Failed to find SPIFFS partition");
        } else {
            GEMINAI_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
        }
        return ESP_FAIL;
    }

    size_t total = 0, used = 0;

    ret = esp_spiffs_info(conf.partition_label, &total, &used);
    if (ret != ESP_OK) {
        GEMINAI_LOGE(TAG, "Failed to get SPIFFS partition information (%s). Formatting...", esp_err_to_name(ret));
        esp_spiffs_format(conf.partition_label);
        return ESP_FAIL;
    } else {
        GEMINAI_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
    }


    if (used > total) {
        GEMINAI_LOGW(TAG, "Number of used bytes cannot be larger than total. Performing SPIFFS_check().");
        ret = esp_spiffs_check(conf.partition_label);
        if (ret != ESP_OK) {
            GEMINAI_LOGE(TAG, "SPIFFS_check() failed (%s)", esp_err_to_name(ret));
            return ESP_FAIL;
        } else {
            GEMINAI_LOGI(TAG, "SPIFFS_check() successful");
        }
    }

    return ESP_OK;
}

static void TraverseDir(char *direntName, int level, int indent)
{
    DIR *p_dir = NULL;
    struct dirent *p_dirent = NULL;


    p_dir = opendir(direntName);

    if (p_dir == NULL) {
        GEMINAI_LOGE(TAG, "opendir %s error:%s\n",direntName,strerror(errno));
        return;
    }

    while ((p_dirent = readdir(p_dir)) != NULL) {
        char *backupDirName = NULL;

        if (p_dirent->d_name[0] == '.') {
            continue;
        }

        int i;

        for (i = 0; i < indent; i++) {
            // printf("|");
            printf("     ");
        }

        printf("|--- %s", p_dirent->d_name);

        /* Itme is a file */
        if (p_dirent->d_type == DT_REG) {
            int curDirentNameLen = strlen(direntName) + strlen(p_dirent->d_name) + 2;

            //prepare next path
            backupDirName = (char *)malloc(curDirentNameLen);
            struct stat *st = NULL;
            st = malloc(sizeof(struct stat));

            if (NULL == backupDirName || NULL == st) {
                goto _err;
            }

            memset(backupDirName, 0, curDirentNameLen);
            memcpy(backupDirName, direntName, strlen(direntName));

            strcat(backupDirName, "/");
            strcat(backupDirName, p_dirent->d_name);

            int statok = stat(backupDirName, st);

            if (0 == statok) {
                printf("[%dB]\n", (int)st->st_size);
            } else {
                printf("\n");
            }

            free(backupDirName);
            backupDirName = NULL;
        } else {
            printf("\n");
        }

        /* Itme is a directory */
        if (p_dirent->d_type == DT_DIR) {
            int curDirentNameLen = strlen(direntName) + strlen(p_dirent->d_name) + 2;

            //prepare next path
            backupDirName = (char *)malloc(curDirentNameLen);

            if (NULL == backupDirName) {
                goto _err;
            }

            memset(backupDirName, 0, curDirentNameLen);
            memcpy(backupDirName, direntName, curDirentNameLen);

            strcat(backupDirName, "/");
            strcat(backupDirName, p_dirent->d_name);

            if (level > 0) {
                TraverseDir(backupDirName, level - 1, indent + 1);
            }

            free(backupDirName);
            backupDirName = NULL;
        }
    }

_err:
    closedir(p_dir);
}

void geminai_print_dir(char *direntName, int level)
{
    printf("Traverse directory %s\n", direntName);
    TraverseDir(direntName, level, 0);
    printf("\r\n");
}

const char *geminai_get_filename(const char *file)
{
    const char *p = file + strlen(file);
    while (p > file) {
        if ('/' == *p) {
            return (p + 1);
        }
        p--;
    }
    return file;
}

size_t geminai_get_file_size(const char *filepath)
{
    struct stat siz =  { 0 };
    stat(filepath, &siz);
    return siz.st_size;
}
